<?php
/**
 * Created By PhpStorm
 * Author: patrick wu
 * Date: 2020/9/30
 * Time: 11:04
 */
namespace App\Utils;

use Carbon\Carbon;
use Illuminate\Support\Facades\Redis;
use GuzzleHttp\Client;
use App\Constant\RedisKeyConstant;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Config;
use App\Http\Model\Mysql\UserModel;
use Illuminate\Support\Facades\URL;

class WechatUtil
{
    const DECRYPT_OK        =   0;
    const ILLEGAL_AES_KEY   =   -41001;
    const ILLEGAL_IV        =   -41002;
    const ILLEGAL_BUFFER    =   -41003;
    const DECODE_BASE64ERROR=   -41004;

    const ERROR_DESC    =   [
        self::ILLEGAL_AES_KEY   =>  '非法密钥',
        self::ILLEGAL_IV        =>  '非法初始向量',
        self::ILLEGAL_BUFFER    =>  '非法缓冲值',
        self::DECODE_BASE64ERROR=>  '非法解析错误',
    ];

    /**
     * 获取微信公用凭证
     * @return mixed|null
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getAccessToken()
    {
        if (!empty($access_token = Redis::GET(RedisKeyConstant::WECHAT_ACCESS_TOKEN))) {
            return $access_token;
        }

        $wechat_config  =   Config::get('wechat');
        $query_client   =   new Client(['verify' => false, 'timeout' => 5]);
        $query_response =   $query_client->get('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $wechat_config['appid'] . '&secret=' . $wechat_config['appsecret']);
        $query_result   =   json_decode($query_response->getBody()->getContents(), true);
        if (isset($query_result['access_token'])) {
            Redis::SETEX(RedisKeyConstant::WECHAT_ACCESS_TOKEN, $query_result['expires_in'], $query_result['access_token']);
            return $query_result['access_token'];
        } else {
            /**
             * 记录错误信息
             */
            $file_name  =   'wechat_access_token_error_' . date('Y_m_d', time()) . '.txt';
            $file_text  =   Carbon::now()->toDateTimeString() . ' 错误信息：' . ($query_result['errmsg'] ?? '获取access_token未知错误');
            Storage::append($file_name, $file_text . PHP_EOL);
            return NULL;
        }
    }

    /**
     * 获取指定参数的小程序码
     * @param array $params   指定参数，必须指定 scene 参数
     * @param int $user_id   用户ID
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getUnlimitedCode(array $params = [], int $user_id = 1)
    {
        if (!isset($params['scene'])) {
            return [false, '场景设置错误'];
        }

        $access_token   =   self::getAccessToken();
        if (empty($access_token)) {
            return [false, 'access_token获取错误'];
        }

        $query_client   =   new Client(['verify' => false, 'timeout' => 5]);
        $query_response =   $query_client->post('https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' . $access_token,  ['json' => $params]);
        $body_contents  =   $query_response->getBody()->getContents();
        $query_result   =   json_decode($body_contents, true);
        /**
         * 如果json解析为空，说明返回的是图片buffer
         */
        if (empty($query_result)) {

            $local  =   "Code/code_example_" . $user_id . ".jpg";
            @copy("Code/code_example.jpg", $local);
            /**
             * 将buffer转换为图片
             */
            $file   =   fopen($local,"w");       //创建件准备写入, 文件名自定义
            fwrite($file, $body_contents);
            fclose($file);
            return [true, ["img_path" => URL::asset($local)]];
        } else {
            if (isset($query_result['errcode']) && $query_result['errcode'] != 0) {
                return [false, $query_result['errmsg']];
            } else {
                return [true, $query_result];
            }
        }
    }

    /**
     * 小程序登录code获取session
     * @param string $js_code
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function codeToSession(string $js_code)
    {
        $wechat_config  =   Config::get('wechat');
        $query_client   =   new Client(['verify' => false, 'timeout' => 5]);
        $query_response =   $query_client->get('https://api.weixin.qq.com/sns/jscode2session?appid=' . $wechat_config['appid'] . '&secret=' . $wechat_config['appsecret'] . '&js_code=' . $js_code . '&grant_type=authorization_code');
        $query_result   =   json_decode($query_response->getBody()->getContents(), true);
        if (isset($query_result['openid']) && isset($query_result['session_key'])) {
            return [true, $query_result];
        } else {
            return [false, $query_result['errmsg'] ?? '小程序错误'];
        }
    }

    /**
     * 检验数据真实性，返回解密后的明文
     * @param string $session_key   用户session_key
     * @param string $encrypted_data 加密后的原文
     * @param string $iv    初始向量值
     * @return array
     */
    public static function decryptData(string $session_key, string $encrypted_data, string $iv)
    {
        if (strlen($session_key) != 24) {
            return [self::ILLEGAL_AES_KEY, self::ERROR_DESC[self::ILLEGAL_AES_KEY]];
        }

        if (strlen($iv) != 24) {
            return [self::ILLEGAL_IV, self::ERROR_DESC[self::ILLEGAL_IV]];
        }

        $aes_key    =   base64_decode($session_key);
        $aes_iv     =   base64_decode($iv);
        $aes_cipher =   base64_decode($encrypted_data);

        $aes_result =   openssl_decrypt($aes_cipher, "AES-128-CBC", $aes_key, 1, $aes_iv);
        $data_result=   json_decode($aes_result, true);

        if ($data_result == NULL || $data_result['watermark']['appid'] != Config::get('wechat.appid')) {
            return [self::ILLEGAL_BUFFER, self::ERROR_DESC[self::ILLEGAL_BUFFER]];
        }

        return [self::DECRYPT_OK, $data_result];
    }
}
